package agent;

import instanceXMLParser.CellLogicalState;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import aima.core.agent.Action;
import aima.core.agent.impl.DynamicAction;

public class AgentsManager {

	List<AbstractVacuumSolver> solvers = new ArrayList<>();

	volatile Map<String, List<Action>> solutions = new HashMap<>();

	volatile List<Action> finalSolution;

	int limitKBEST = 100;

	List<Thread> threads = new ArrayList<>();

	public AgentsManager(int KBEST, int n, int m, List<Integer> AllTargetCells,
			CellLogicalState[][] partialBoard, Point agentStartPos, Point basePoint,
			double energy) {
//		limitKBEST = KBEST;
		limitKBEST = calcBEST_KBEST(AllTargetCells.size());
		for (int i =0; i < limitKBEST; i++) {
			solvers.add(new VacuumAgentSolverHeuristicKBest(i+1, n, m,
					AllTargetCells, partialBoard, agentStartPos, basePoint, energy));
		}
	}

	public List<Action> solve() {
		//manca il perfect solver
		
		for (int i = 0; i < limitKBEST; i++) {
			VacuumAgentSolverHeuristicKBest solverI = (VacuumAgentSolverHeuristicKBest) solvers
					.get(i);
			Thread thread = new Thread(solverI);
			threads.add(thread);
			thread.start();

		}

		for (int i = 0; i < limitKBEST; i++) {

			try {
				threads.get(i).join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			solutions.put(((VacuumAgentSolverHeuristicKBest) solvers.get(i))
					.getId(),
					((VacuumAgentSolverHeuristicKBest) solvers.get(i))
							.getSolution());
			//System.err.println("((VacuumAgentSolverHeuristicKBest) solvers.get(i)).getSolution( ) : "+((VacuumAgentSolverHeuristicKBest) solvers.get(i))
									//.getSolution());
		}

		finalSolution = bestSolution();

		return finalSolution;

	}

	private List<Action> bestSolution() {
		List<String> keys = new ArrayList<>();
		keys.addAll(solutions.keySet());
		String bestId = "";
		double bestPM = Double.MIN_VALUE;
		for (String id : keys) {
			//System.err.println("dim key : "+keys.size());
			int numSucked = 0;
			// -1 perch il noop non va considerato
			int moviments = -1;
			for (Action act : solutions.get(id)) {
				if (((DynamicAction) act).getName().equals("suck")) {
					numSucked++;
				} else {
					moviments++;
				}
			}
			//System.err.println("numsucked "+solutions.get(id).size());
			if (numSucked > bestPM) {
				bestId = id;
				bestPM = numSucked;
				
			}

		}
		

		return solutions.get(bestId);

	}
	
	private int calcBEST_KBEST(int nUMtargetCells) {

		long LIMITCOMBINAZIONS = 10000;
		int count = 1;

		long combinations = binomial_coefficient(nUMtargetCells, count);

		if (combinations == 0)
			return 1;

		while (combinations > 0 && combinations < LIMITCOMBINAZIONS) {
			combinations = binomial_coefficient(nUMtargetCells, count);
			if (combinations > 0 && combinations < LIMITCOMBINAZIONS)
				count++;
		}

//		//System.err.println("LIMIT = " + count);
		return count;

	}

	static long binomial_coefficient(int n, int k) {

		long coeff = 1;
		for (int i = n - k + 1; i <= n; i++) {
			coeff *= i;
		}
		for (int i = 1; i <= k; i++) {
			coeff /= i;
		}
		return coeff;

	}
}
